﻿using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Shapes;
using System.Windows.Media;
using System.Windows.Media.Media3D;
using System.Windows.Media.Animation;
using Bling.DSL;
using Bling.Properties;
using Bling.Animation;
using Bling.WPF;
using Bling.Slides;
using Bling.Util;
using Bling.Linq;
using Bling.Physics;
using System.Collections.Generic;

namespace Bling.PhysicsTutorial {
  public class Driver : SlideHolder {
    private static readonly GetProperty<Driver, Point> ShakeProperty = "Shake".NewProperty<Driver, Point>();
    public PointBl Shake {
      get { return ShakeProperty[this]; }
      set { Shake.Bind = value; }
    }
    public void Init(Window w) {
      Shake = ((Window)w).Bl().LeftTop;
    }
    public Driver() {
      var methods = typeof(System.Windows.Media.Media3D.Vector3D).GetMethods();

      //this["CurtainB"] = () => new Curtain();
      //this["Title"] = () => new Title();
      this["Strip"] = () => new Strip();
      this["Goo"] = () => new GooCursor();
      this["Sliders"] = () => new Sliders();
      this["Chain"] = () => new Chain();
      this["Octopus"] = () => new Octopus();
      this["Bezier"] = () => new BezierTest();
      this["ShapeIntro"] = () => new ShapeIntro();
      this["Slinky"] = () => new Slinky();
      this["Fireworks"] = () => new Fireworks();
      this["Immediate"] = () => new Immediate();
      this["Curtain"] = () => new NewCurtain();
      //this["Curtain3D"] = () => new Curtain3D();
      this["Collision"] = () => new CollisionInverse() { Shake = Shake };
      this["Popcorn"] = () => new Popcorn() { Shake = Shake };
      this["Trail"] = () => new TrailCursor();
      Init();
    }
    [STAThread]
    public static void Main(string[] args) {


      var win = new Window() { Title = "Bling Physics Tutorial", Content = new Driver() };
      win.Bl().Size = new PointBl(860, 768);
      
      ((Driver)win.Content).Init(win);

      new Application().Run(win);
      return;
    }
  }
  public class Title : PhysicsCanvas {
    public class CustomBlock : PhysicsBlock<Label, LabelBl, CustomBlock>,
      ParticleBody.Is<CustomBlock>, RigidBody.Is<CustomBlock>, ShapeBody.Is<CustomBlock>, MouseAdapter.Is<Label, CustomBlock> {
      public CustomBlock(World World, int Count, Func<int, Label> MakeT)
        : base(World, Count, MakeT) {
        new ParticleBody.Impl<CustomBlock>(this) {
          Loss = .1
        };
        new RigidBody.Impl<CustomBlock>(this);
        new ShapeBody.Impl<CustomBlock>(this);
        new MouseAdapter.Impl<Label,CustomBlock>(this);
      }
    }

    public Title() : base("Title", 10) {
      this.Bl().Background = Brushes.MidnightBlue;
    }
    protected override Action Init(CanvasBl MainCanvas, World World) {
      var Text = "Bling UI Physics";
      var SizeSlider = new SliderBl(MainCanvas) {
        Width = MainCanvas.Width, RightBottom = MainCanvas.Size,
        Minimum = 0, Maximum = 1, Value = 1,
      };
      SizeSlider.Value = SizeSlider.Minimum;
      SizeSlider.Value.Animate.Forever().AutoReverse().To = SizeSlider.Maximum;

      var Size = new PointBl(50, 100) * (SizeSlider.Value.Lerp(.1, 1.5));

      var block = new CustomBlock(World, Text.Length, (idx) => {
        var lbl = new LabelBl(MainCanvas) {
          Content = new Constant<object>(Text[idx]),
          Font = { Weight = FontWeights.SemiBold, Brush = Brushes.Yellow, },
          //EnableCenterScale = true,
        };
        lbl.CurrentValue.Padding = new Thickness(0);
        lbl.RenderTransform.Scale = Size / lbl.Size;
        return lbl;
      }) {
        Name = "Letters",
      };
      //block.ShapeBodyE().Scale = (body) => Size / block[body.Index].At.Size;


      PointBl Origin = new PointBl(10, MainCanvas.Size.Y / 2 - Size.Y / 2);

      block.ShapePoints().BindRect(Size);

      block.ShapeBodyE().RelaxNext = (block0) => {
        block0.ForAll(body => {
          body.Rotation().Relax[(1d-SizeSlider.Value)*.01] = 0.ToPI();
          body.Center().Relax[(1d-SizeSlider.Value)*.01] = new PointBl(10d + Size.X / 2d + (body.Index * Size.X), MainCanvas.Size.Y / 2);
        });
      };


      block.CustomInit = (block0) => {
        for (int i = 0; i < block0.Count; i++) {
          //block0[i].At.CenterScale = Size / block0[i].At.Size;
        }
        block0.ConnectBlock();

        block0.ForAll(body => {
          body.Particles().ForAll(particle => {
            particle.Position.Relax[.5, body.Index > 0] =
              particle.Position.Spring(body.Prev[1].Particles(particle.Index), Size.X);
            particle.Position.Relax[.5, body.Index < block0.Count - 1] =
              particle.Position.Spring(body.Next[1].Particles(particle.Index), Size.X);

            particle.Position.Old = particle.Position.Old.Restitution(particle.Position, new Point(0, 0), MainCanvas.Size);
            //particle.Position = particle.Position.Clamp(new PointBl(0, 0), MainCanvas.Size);
          });
        });
      };




      return () => { };
    }



  }

}
